package handler

import (
	"slices"
	"strconv"
	"strings"
	"time"
	"trader/apps/common/resp"
	"trader/constant"
	"trader/models"

	"github.com/gin-gonic/gin"
	"xorm.io/xorm"
)

type TransRecordHandler struct {
	Engine *xorm.Engine
}

func NewTransRecord(engine *xorm.Engine) *TransRecordHandler {
	return &TransRecordHandler{Engine: engine}
}

type TransRecordCreateRequest struct {
	Date     string  `form:"date" json:"date" binding:"required"`
	Action   int     `json:"action" binding:"required,oneof=-1 1"`
	Price    float64 `json:"price" binding:"required,gt=0"`
	Quantity int64   `json:"quantity" binding:"required,gt=0"`
	Reason   string  `json:"reason" binding:"omitempty,lte=255"`
}

func (h TransRecordHandler) Create(c *gin.Context) {
	var err error
	planId := c.GetInt64("planId")
	stockId := c.GetInt64("stockId")

	finished, err := h.Engine.Where("id=? and status=?", planId, constant.Finish).Exist(new(models.TransactionPlan))
	if finished {
		resp.FailParamf(c, "计划已完结")
		return
	}

	var req TransRecordCreateRequest
	if err = c.ShouldBindJSON(&req); err != nil {
		resp.FailParam(c, err)
		return
	}

	transDate, err := time.Parse(time.DateOnly, req.Date)
	if err != nil {
		resp.FailParamf(c, "日期格式错误：%s", req.Date)
		return
	}

	newRecord := models.TransactionRecord{
		PlanId:   planId,
		StockId:  stockId,
		Date:     transDate,
		Action:   req.Action,
		Price:    req.Price,
		Quantity: req.Quantity,
		Reason:   req.Reason,
		ParentId: 0,
	}

	lastRecord := new(models.TransactionRecord)
	exist, _ := h.Engine.Where("plan_id=? and stock_id=?", planId, stockId).OrderBy("-id").Get(lastRecord)
	if exist {
		newRecord.ParentId = lastRecord.Id
	}

	_, err = h.Engine.Insert(newRecord)
	if err != nil {
		resp.FailDB(c, err)
		return
	}

	resp.OK(c, "添加成功", gin.H{"id": newRecord.Id})
}

type TransRecordUpdateRequest struct {
	Action   int     `json:"action" binding:"required,oneof=-1 1"`
	Price    float64 `json:"price" binding:"required,gt=0"`
	Quantity int64   `json:"quantity" binding:"required,gt=0"`
	Reason   string  `json:"reason" binding:"omitempty,lte=255"`
}

func (h TransRecordHandler) Update(c *gin.Context) {
	var err error
	planId := c.GetInt64("planId")

	finished, err := h.Engine.Where("id=? and finish=1", planId).Exist(new(models.TransactionPlan))
	if finished {
		resp.FailParamf(c, "计划已完结")
		return
	}
	id, err := strconv.ParseInt(c.Param("trans_id"), 10, 64)
	if err != nil {
		resp.FailParam(c, err)
		return
	}

	var req TransRecordUpdateRequest
	if err = c.ShouldBindJSON(&req); err != nil {
		resp.FailParam(c, err)
		return
	}

	_, err = h.Engine.Table(new(models.TransactionRecord)).
		Where("plan_id=? and id=?", planId, id).
		Cols("action", "price", "quantity", "reason").
		Update(map[string]any{
			"action":   req.Action,
			"price":    req.Price,
			"quantity": req.Quantity,
			"reason":   req.Reason,
		})
	if err != nil {
		resp.FailDB(c, err)
		return
	}

	resp.OKWithoutData(c, "更新成功")
}

func (h TransRecordHandler) Get(c *gin.Context) {
	var err error
	planId := c.GetInt64("planId")

	id, err := strconv.ParseInt(c.Param("trans_id"), 10, 64)
	if err != nil {
		resp.FailParam(c, err)
		return
	}

	record := new(models.TransactionRecord)
	_, err = h.Engine.Where("id=? and plan_id=?", id, planId).Get(record)
	if err != nil {
		resp.FailDB(c, err)
		return
	}

	resp.OK(c, "ok", record)
}

func (h TransRecordHandler) Delete(c *gin.Context) {
	var err error
	planId := c.GetInt64("planId")

	finished, err := h.Engine.Where("id=? and finish=1", planId).Exist(new(models.TransactionPlan))
	if finished {
		resp.FailParamf(c, "计划已完结")
		return
	}
	id, err := strconv.ParseInt(c.Param("trans_id"), 10, 64)
	if err != nil {
		resp.FailParam(c, err)
		return
	}

	_, err = h.Engine.Where("plan_id=? and id=?", planId, id).Delete(new(models.TransactionRecord))
	if err != nil {
		resp.FailDB(c, err)
		return
	}

	resp.OKWithoutData(c, "已删除")
}

func (h TransRecordHandler) List(c *gin.Context) {
	var err error
	planId := c.GetInt64("planId")

	records := make([]models.TransactionRecord, 0)
	err = h.Engine.Where("plan_id=?", planId).OrderBy("-id").Find(&records)
	if err != nil {
		resp.FailDB(c, err)
		return
	}

	// 按照日期对交易记录进行聚合
	dateTrans := make(map[string][]models.TransactionRecord)
	for _, record := range records {
		date := record.Date.Format(time.DateOnly)
		if _, ok := dateTrans[date]; !ok {
			dateTrans[date] = make([]models.TransactionRecord, 0)
		}
		dateTrans[date] = append(dateTrans[date], record)
	}

	type DateTrans struct {
		Date  string                     `json:"date"`
		Trans []models.TransactionRecord `json:"trans"`
	}

	data := make([]DateTrans, 0)
	for date, dateRecords := range dateTrans {
		data = append(data, DateTrans{Date: date, Trans: dateRecords})
	}

	slices.SortFunc(data, func(a, b DateTrans) int {
		return -strings.Compare(a.Date, b.Date)
	})

	resp.OK(c, "ok", data)
}
